//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  ThisAddIn.cs
//    
// Abstract:
//
//  The main entry point for the Enhanced Reminders Outlook add-in.
//  
//--

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.EnhancedReminders.OutlookAddIn;
using Microsoft.Office.Interop.Outlook;
using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders
{
    public partial class ThisAddIn
    {
        #region Privates

        // Outlook inspectors collection
        private Inspectors _inspectors;

        #endregion

        #region Statics

        // List of tracked Inspector windows
        private static List<OutlookReminderInspector> _windows;

        private const string _sourceName = "Microsoft Enhanced Reminders Outlook Add-In";

        #endregion

        #region Event Handlers

        /// <summary>
        /// Startup method invoked by Outlook for each add-in. This is when we subscribe to the 
        /// appropriate events and creates a search folder
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            Debug.Assert(sender != null, "Sender shouldn't be null");
            Debug.Assert(e != null, "EventArgs shouldn't be null");

            Debug.Assert(Application != null, "Application shouldn't be null");
            Debug.Assert(Application.Inspectors != null, "Inspectors shouldn't be null");

#if DEBUG
            // Initialize logging. Diagnostic logs always go to System.Diagnostics.Trace on debug builds.
            Logger.Initialize(_sourceName, TraceLogLevel.All, true /* traceOutput */, false /* enableOperationalLogs */);
#else
            // Initialize logging. Diagnostic logs never go to System.Diagnostics.Trace on retail builds. 
            Logger.Initialize(_sourceName, TraceLogLevel.All, false /* traceOutput */, false /* enableOperationalLogs */);
#endif

            _inspectors = Application.Inspectors;
            _inspectors.NewInspector += NewInspector;

            _windows = new List<OutlookReminderInspector>();

            Application.OptionsPagesAdd += OnOptionsPagesAdd;
        }

        /// <summary>
        /// NewInspector event handler.
        /// </summary>
        /// <param name="inspector">The inspector window.</param>
        private void NewInspector(Inspector inspector)
        {
            Debug.Assert(inspector != null, "Inspector shouldn't be null");

            Debug.Assert(inspector.CurrentItem != null, "Inspector should have a CurrentItem");
            AppointmentItem appointment = inspector.CurrentItem as AppointmentItem;

            // Make sure this is an appointment item
            if (appointment != null)
            {
                // Check to see if this is a new window 
                // we don't already track
                OutlookReminderInspector existingWindow = FindOutlookInspector(inspector);

                // If the _windows collection does not have a window for this Inspector,
                // we should add it to _windows
                if (existingWindow == null)
                {
                    OutlookReminderInspector window = new OutlookReminderInspector(inspector);
                    Debug.Assert(window != null, "Failed to create OutlookReminderInspector");

                    window.Closed += WrappedWindow_Closed;
                    _windows.Add(window);
                }
            }
        }

        /// <summary>
        /// Remove Inspector window wrapper from our internal list so that we don't get
        /// events from it
        /// </summary>
        private void WrappedWindow_Closed(object sender, EventArgs e)
        {
            Debug.Assert(sender != null, "Sender shouldn't be null");
            Debug.Assert(e != null, "EventArgs shouldn't be null");

            OutlookReminderInspector window = Helpers.AssertCast<OutlookReminderInspector>(sender);
            window.Closed -= WrappedWindow_Closed;
            _windows.Remove(window);

            // Required to ensure Outlook updates the appointment if the reminder item has changed
            // in the meantime.  The scheduler might have just applied a calendar rule and updated 
            // this appointment in the background.  Not releasing this object prevents us from
            // viewing the updated reminder.
            OutlookUtils.ForceRelease(window.Window);
        }

        /// <summary>
        /// Add a custom property page to the Outlook Tools->Options property pages.
        /// </summary>
        private void OnOptionsPagesAdd(PropertyPages pages)
        {
            Debug.Assert(pages != null, "pages");

            // Add the property page Winform control which contains the XAML
            // property page.  Pass in null for the Title parameter as this is
            // ignored.  Instead the property page queries the control for
            // Title property.
            pages.Add(new NotificationRulesContainer(), /*string Title*/null);
        }

        /// <summary>
        /// Cleans up resources.
        /// </summary>
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            Debug.Assert(sender != null, "Sender shouldn't be null");
            Debug.Assert(e != null, "Event argument shouldn't be null");

            // Unhook event handlers
            Debug.Assert(_inspectors != null, "_inspector shouldn't be null");
            _inspectors.NewInspector -= NewInspector;

            // Dereference objects
            _inspectors = null;

            Debug.Assert(_windows != null, "_windows shouldn't be null");
            _windows.Clear();
            _windows = null;

            Logger.Close();
        }

        #endregion EventHandlers

        #region Static methods

        /// <summary>
        /// Looks up the window wrapper for a given window object
        /// </summary>
        /// <param name="window">An outlook inspector window</param>
        /// <returns>An OutlookReminderInspector wrapping the inspector</returns>
        internal static OutlookReminderInspector FindOutlookInspector(object window)
        {
            Debug.Assert(_windows != null, "_windows shouldn't be null");
            Debug.Assert(window != null, "window shouldn't be null");

            foreach (OutlookReminderInspector inspector in _windows)
            {
                if (inspector.Window == window)
                {
                    return inspector;
                }
            }
            return null;
        }

        #endregion Static methods

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            Startup += new System.EventHandler(ThisAddIn_Startup);
            Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }

        #endregion
    }
}
